#include <sb/sb.h>

// option
static struct Option
{
	kbool				nologo;
	kbool				msstyle;
	kbool				dorun;
	kbool				outobj;
	kbool				outmne;
	kbool				outlog;
	char				filename[260];
	char				objfile[260];
	char				mnefile[260];
	int					outlevel;

	char				hsname[260];
} g_opt =
{
	FALSE,
};

// logo
static void logo(void)
{
	if (g_opt.nologo || g_opt.dorun)
		return;

	k_outputf(\
		"- HS script compiler version 0.6.1.311\n"\
		"Build by ksh 2007, 2008, 2009, 2010, 2011, 2012, 2013\n"\
		"\n");

	g_opt.nologo = TRUE;
}

// usage
static void usage(void)
{
	k_outputf("\n"
		"usage: %s [option ...] filename\n\n"
		"-c[=filename] create object file. (not implementation)\n"
		"-a[=filename] create compile parse file.\n"
		"-r            run script.\n"
		"-n            do not display logo.\n"
		"-l            enable output logging.\n"
		"-ms           enable microsoft compiler style.\n"
		"-pX           set output level. (0=error, 1=result, 2=all)\n"
		"\n", g_opt.hsname);
}

// main
int main(int argc, char* argv[])
{
	char str[260];
	char drv[12];
	char dir[260];
	char name[260];
	char ext[260];
	kint i, err, ret;
	kHsm* hsm;
	kRnh* run;
	kRedFn* rfn;

	// parse self
	k_splitpath(argv[0], drv, 11, dir, 259, g_opt.hsname, 259, ext, 259);

	// argc check
	if (argc == 1)
	{
		logo();
		usage();
		return 0;
	}

	// check self filename for dorun
	g_opt.dorun = !k_strieqv(g_opt.hsname, "hsc");

	// argument parse
	str[0] = '\0';
	err = FALSE;
	for (i = 1; i < argc; i++)
	{
		if (argv[i][0] == '-' /*|| argv[i][0]=='/'*/)
		{
			switch (argv[i][1])
			{
				case 'c':
					g_opt.outobj = TRUE;
					if (argv[i][2] == '=')
						k_strncpy(g_opt.objfile, &argv[i][3], 259);
					else if (argv[i][2] != '\0')
					{
						k_snprintf(str, 259, "%s : command line error 0003: '-c' option need '='.\n\n", g_opt.hsname);
						err = TRUE;
					}
					break;

				case 'a':
					g_opt.outmne = TRUE;
					if (argv[i][2] == '=')
						k_strncpy(g_opt.mnefile, &argv[i][3], 259);
					else if (argv[i][2] != '\0')
					{
						k_snprintf(str, 259, "%s : command line error 0004 : '-a' option need '='.\n\n", g_opt.hsname);
						err = TRUE;
					}
					break;

				case 'r':
					g_opt.dorun = TRUE;
					break;

				case 'n':
					g_opt.nologo = TRUE;
					break;

				case 'm':
					if (argv[i][2] == 's')
						g_opt.msstyle = TRUE;
					break;

				case 'p':
					ret = argv[i][2] - '0';
					if (ret >= 1 && ret <= 2)
						g_opt.outlevel = ret;
					break;

				default:
					k_snprintf(str, 259, "%s : command line warning 0002 : '%s' is unknown option.\n\n", g_opt.hsname, &argv[i][1]);
					break;
			}
		}
		else
		{
			k_strncpy(g_opt.filename, argv[i], 259);
		}
	}

	logo();

	if (g_opt.outlevel > 0)
	{
		static kuint s_lvl[] =
		{
			KLV_ERROR,
			KLV_RESULT,
			KLV_ALL,
		};
		k_setlv(s_lvl[g_opt.outlevel]);
	}

	if (!*g_opt.filename)
	{
		k_snprintf(str, 259, "%s : command line error 0001 : missing filename.\n\n", g_opt.hsname);
		err = TRUE;
	}

	if (err)
	{
		k_output(str);
		return 0;
	}

	// split filename
	k_splitpath(g_opt.filename, drv, 11, dir, 259, name, 259, ext, 259);

	// check file
	if (!k_file_exist(g_opt.filename, NULL))
	{
		k_snprintf(str, 259, "%s%s%s.hs", drv, dir, name);

		if (!k_file_exist(str, NULL))
		{
			k_outputf("%s : command line error 0005 : cannot open file.\n\n", g_opt.hsname);
			return 0;
		}

		k_strcpy(g_opt.filename, str);
	}

	// output filename
	if (!*g_opt.objfile)
		k_snprintf(g_opt.objfile, 259, "%s%s%s.hsa", drv, dir, name);
	if (!*g_opt.mnefile)
		k_snprintf(g_opt.mnefile, 259, "%s%s%s.txt", drv, dir, name);

	// ok go!
	hsm = k_hsm_new(0);

	rfn = k_hsm_compile_file(hsm, NULL, g_opt.filename, g_opt.outmne ? g_opt.mnefile : NULL, NULL);
	if (!rfn)
	{
		k_outputf("%s : command line error 0006 : cannot compile script.\n\n", g_opt.hsname);
		ret = 0;
	}
	else
	{
		if (!g_opt.dorun)
			ret = 0;
		else
		{
			run = k_hsm_create_run(hsm, rfn, NULL);
			if (run)
			{
				kVar v;
				k_rnh_run_main(run, &v);

				if (k_var_is_not_null(&v))
				{
					if (k_var_is_int(&v))
						ret = k_var_unsafe_int(&v);
					else
					{
						char sz[1024];
						const char* psz;
						kBstr1k bs;

						ret = 0;
						psz = k_var_tos(&v, sz, 1024 - 1, NULL);

						k_bstr_init(&bs, "[return -> ");
						k_bstr_append(&bs, psz);
						k_bstr_append(&bs, "]\n");

						k_output_utf8(bs.data);
					}

					k_var_unload(&v);
				}

				k_base_unload((kBase*)run);
			}
		}

		k_base_unload((kBase*)rfn);
	}

	k_base_unload((kBase*)hsm);

	return ret;
}
